package com.baihejia.common.dubbo.server;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;

import com.baihejia.common.dubbo.domain.Area;
import com.baihejia.common.dubbo.domain.BusinessArea;
import com.baihejia.common.dubbo.domain.City;
import com.baihejia.common.dubbo.domain.Community;
import com.baihejia.common.dubbo.domain.CommunityEsPage;
import com.baihejia.common.dubbo.domain.CommunityQuery;
import com.baihejia.common.dubbo.domain.Page;
import com.baihejia.common.dubbo.domain.Subway;
import com.baihejia.common.dubbo.domain.SubwayQuery;
import com.baihejia.common.dubbo.domain.SubwayQueryResult;
import com.baihejia.common.dubbo.domain.SubwayStation;
import com.baihejia.common.dubbo.domain.SubwayStationRelation;
import com.baihejia.common.dubbo.server.cache.CacheKey;
import com.baihejia.common.dubbo.server.cache.RDSCache;
import com.baihejia.common.dubbo.server.cache.aop.ListCache;
import com.baihejia.common.dubbo.server.cache.aop.SimpleCache;
import com.baihejia.common.dubbo.server.libs.Constants;
import com.baihejia.common.dubbo.server.libs.DB;
import com.baihejia.common.dubbo.service.Api;

/**
 * @author hanxipeng
 */
public class ApiImpl implements Api {

    private static CommunityClient communityClient = new CommunityClient();
    
    private static SubwayClient subwayClient = new SubwayClient();
    
	@Override
	public CommunityEsPage getCommunitys(CommunityQuery query) {
		Page<String> searchCommunity = searchCommunity(query);
		List<Long> ids = searchCommunity.items.stream().map(Long :: valueOf).collect(Collectors.toList());
		List<Community> communitys = RDSCache.mget(Community.class, ids);
		return new CommunityEsPage(communitys, searchCommunity.count, searchCommunity.showCount);
	}
	
	@Override
	public City city(long cityId) {
		return RDSCache.get(City.class, cityId);
	}
	
	@Override
	public Page<String> searchCommunity(CommunityQuery query){
		try {
			return communityClient.search(query);
		} catch (Exception e) {
			Logger.error(e, e.getMessage());
			throw new RuntimeException(e);
		}
	}

	@Override
    @ListCache(keyPrefix = CacheKey.subwaysByCityId, expires = 24 * 3600)
    public List<Subway> subways(long cityId){
        return DB.find(Subway.class, "cityId=? order by sort", cityId);
    }

	@Override
	public SubwayStation subwayStation(long subwayStationId) {
		return RDSCache.get(SubwayStation.class, subwayStationId);
	}

	@Override
	public Area area(long areaId) {
		return RDSCache.get(Area.class, areaId);
	}

	@Override
    @ListCache(keyPrefix = CacheKey.areasByCityId, expires = 24 * 3600)
    public List<Area> areas(long cityId){
        return DB.find(Area.class, "cityId=? order by sort,id", cityId);
    }

	@Override
	public BusinessArea businessArea(long businessAreaId) {
		return RDSCache.get(BusinessArea.class, businessAreaId);
	}

	@Override
    @ListCache(keyPrefix = CacheKey.businessAreasByAreaId, expires = 24 * 3600)
    public List<BusinessArea> businessAreas(long areaId){
        return DB.find(BusinessArea.class, "areaId=? order by id", areaId);
    }

	@Override
	public Community getCommunityById(long id) {
		return RDSCache.get(Community.class, id);
	}

	@Override
    @SimpleCache(keyPrefix = CacheKey.getCityByListName, expires = 24 * 60 * 60)
    public City getCityByListName(String listName) {
        return DB.findFirst(City.class, "listName=?", listName);
    }

	@Override
	public List<SubwayQueryResult> nearSubwayByCityAndLatAndLon(SubwayQuery subwayQuery) {
		List<SubwayQueryResult> subwayQueryResults = new ArrayList<>();
		try {
			Page<String> page = subwayClient.search(subwayQuery);
			List<String> idsList = page.items;
			List<Long> ids = idsList.stream().map(Long::valueOf).collect(Collectors.toList());
			List<SubwayStation> subwayStations = RDSCache.mget(SubwayStation.class, ids);
			if(subwayStations.isEmpty()){
				return subwayQueryResults;
			}
			List<SubwayStationRelation> relations = DB.find(SubwayStationRelation.class,String.format("subwayStationId in (%s) order by sort", StringUtils.join(subwayStations.stream().map(station->station.id).collect(Collectors.toList()),",")));
			for (SubwayStation subwayStation : subwayStations) {
				for (SubwayStationRelation relation : relations.stream().filter(rel-> rel.subwayStationId== subwayStation.id).collect(Collectors.toList())) {
					SubwayQueryResult result = new SubwayQueryResult();
					result.subwayId = relation.subwayId;
					result.subwayStationId = subwayStation.id;
					result.distance = Constants.getDistance(subwayStation.lon, subwayStation.lat, subwayQuery.lon, subwayQuery.lat);
					subwayQueryResults.add(result);
				}
			}
			return subwayQueryResults;
		} catch (Exception e) {
//			throw new RuntimeException(e);
			Logger.error(e.getMessage(), e);
		}
		return new ArrayList<>();
	}
}
